package org.interaction3d.assembly.convert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 *
 * @author Michael Nischt
 */
public class Vertices
{
    private final List<int[]> indexList = new ArrayList<int[]>();

    public int apply(int... indices)
    {
        if(indices.length < 1)
        {
            throw new IllegalArgumentException();
        }

        return add(indexList, indices);
    }

    public int[][] attributes()
    {
        return indexList.toArray(new int[indexList.size()][]);
    }

    private static int add(List<int[]> indexList, int[] index)
    {
        int size = indexList.size();
        for (int i = 0; i < size; i++) if (equals(indexList.get(i), index))
        {
            return i;
        }
        indexList.add(index);
        return size;
    }

    private static boolean equals(int[] o1, int[] o2)
    {
        if(o1.length != o1.length)
        {
            return false;
        }        
        int count = o1.length;

        for (int i = 0; i < count; i++)
        {
            if (o1[i] != o2[i])
                return false;
        }
        return true;
    }


    // <editor-fold defaultstate="collapsed" desc="sort">

    static public int[] sort(final int[][] vertices, int index)
    {
        final int[] id = new int[vertices.length];
        for (int i = 0; i < id.length; i++)
        {
            id[i] = i;
        }

        final List<Pair> list = new java.util.AbstractList<Pair>()
        {
            @Override
            public Pair get(int index)
            {
                return new Pair(vertices[index], id[index]);
            }

            @Override
            public Pair set(int index, Pair pair)
            {
                Pair old = get(index);
                vertices[index] = pair.vertex;
                id[index] = pair.id;
                return old;
            }

            @Override
            public int size()
            {
                return vertices.length;
            }
        };

        Collections.sort(list, new PairComparator(index));

        int[] map = new int[id.length];
        for(int i=0; i<id.length; i++)
        {
            map[id[i]] = i;
        }

        return map;
    }

    static private final class PairComparator implements Comparator<Pair>
    {
        private final int index;

        public PairComparator(int index)
        {
            this.index = index;
        }

        public int compare(Pair o1, Pair o2)
        {
            return o1.vertex[index] - o2.vertex[index];
        }
    }

    static private final class Pair
    {
        public final int[] vertex;
        public final int id;

        public Pair(int[] first, int second)
        {
            this.vertex = first;
            this.id = second;
        }
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="transpose">

    public static int[][] transpose(int[][] matrix)
    {
        int rows = matrix.length;
        int cols = matrix[0].length;

        int[][] transpose = new int[cols][rows];

        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                transpose[j][i] = matrix[i][j];
            }
        }
        return transpose;
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="reduce">

    public static int[][] reduce(int[][] maps, int[] mapIndices)
    {
        if (mapIndices.length != maps.length)
        {
            throw new IllegalArgumentException();
        }

        int index = 0;

        for (int i=0; i<mapIndices.length; i++)
        {
            mapIndices[i] = index++;

            if (isId(maps[i]))
            {
                mapIndices[i] = -1;
                index--;
                continue;
            }
            for (int j=i-1; j>=0; j--)
            {
                if (areEqual(maps[i], maps[j]))
                {
                    mapIndices[i] = mapIndices[j];
                    index--;
                    break;
                }
            }
        }

        int[][] newMaps = new int[index][];
        index = 0;
        for(int i=0; i<mapIndices.length; i++)
        {
            if(mapIndices[i] >= 0 && newMaps[mapIndices[i]] == null)
            {
                newMaps[index++] = maps[i];
            }
        }
        return newMaps;
    }

    public static boolean isId(int... vector)
    {
        for (int i = 0; i < vector.length; i++)
            if (i != vector[i])
            {
                return false;
            }
        return true;
    }

    public static boolean areEqual(int[] a, int[] b)
    {
        if (a.length != b.length)
            throw new IllegalArgumentException();

        for (int i = 0; i < a.length; i++)
            if (a[i] != b[i])
            {
                return false;
            }
        return true;
    }

    // </editor-fold>
}